package keqiang.com.kq_flutter_core_widget.util.qq;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.keqiang.base.Logger;
import com.tencent.connect.common.Constants;
import com.tencent.connect.share.QQShare;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
import keqiang.com.kq_flutter_core_widget.BuildConfig;
import keqiang.com.kq_flutter_core_widget.util.ErrCode;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * 提供与qq操作Api
 *
 * @author Created by wanggaowan on 2024/12/18 下午3:52
 */
public class QQAPI {
    private static final String TAG = QQAPI.class.getSimpleName();
    private static final int SHARE_TEXT = 0xFF01;
    
    private static QQAPI mWxApi;
    
    private final String mAppId;
    private final Tencent mApi;
    private final QQApiEventHandlerImpl mLoginEventHandler = new QQApiEventHandlerImpl();
    private final QQApiEventHandlerImpl mShareEventHandler = new QQApiEventHandlerImpl();
    
    private QQAPI(@NonNull Context context, @NonNull String appId) {
        mAppId = appId;
        String authority = null;
        try {
            ProviderInfo providerInfo = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                providerInfo = context.getPackageManager().getProviderInfo(new ComponentName(context, QQFileProvider.class), PackageManager.ComponentInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
            } else {
                providerInfo = context.getPackageManager().getProviderInfo(new ComponentName(context, QQFileProvider.class), PackageManager.MATCH_DEFAULT_ONLY);
            }
            authority = providerInfo.authority;
        } catch (PackageManager.NameNotFoundException e) {
            // ignore
        }
        if (TextUtils.isEmpty(authority)) {
            mApi = Tencent.createInstance(appId, context);
        } else {
            mApi = Tencent.createInstance(appId, context, authority);
        }
        Tencent.setIsPermissionGranted(true);
    }
    
    @NonNull
    static QQAPI getApi(@NonNull Context context, @NonNull String appId) throws IllegalArgumentException {
        if (TextUtils.isEmpty(BuildConfig.QQ_APP_ID)) {
            throw new IllegalArgumentException("\nqq app id为空, 请在项目pubspec.yaml中添加以下配置(kq_flutter_core_widget与dependencies同级):" +
                "\nkq_flutter_core_widget:\n  qq_app_id: 申请的appId\n");
        }
        
        if (!BuildConfig.QQ_APP_ID.equals(appId)) {
            Logger.w(TAG, "appId: " + appId + "与配置 kq_flutter_core_widget:  qq_app_id: " + BuildConfig.QQ_APP_ID + " 不一致");
        }
        
        if (mWxApi == null || mWxApi.mApi == null || !appId.equals(mWxApi.mAppId)) {
            mWxApi = new QQAPI(context, appId);
        }
        return mWxApi;
    }
    
    public static boolean handIntent(int requestCode, int resultCode, @Nullable Intent intent) {
        QQAPI api = QQAPI.mWxApi;
        if (api == null) {
            return false;
        }
        
        switch (requestCode) {
            case Constants.REQUEST_LOGIN:
                return Tencent.onActivityResultData(requestCode, resultCode, intent, api.mLoginEventHandler);
            case Constants.REQUEST_QQ_SHARE:
            case Constants.REQUEST_QZONE_SHARE:
                return Tencent.onActivityResultData(requestCode, resultCode, intent, api.mShareEventHandler);
            case SHARE_TEXT:
                api.mShareEventHandler.onCallback(ErrCode.SUCCESS, null, null);
                return true;
            default:
                return false;
        }
    }
    
    private static void parseLoginResp(int code, String openId, String accessToken, LoginCallback callback) {
        callback.callback(code, openId, accessToken);
        if (BuildConfig.DEBUG) {
            if (code == ErrCode.CANCEL) {
                Logger.e(TAG, "用户取消授权");
            } else if (code != ErrCode.SUCCESS) {
                Logger.e(TAG, "授权失败");
            } else {
                Logger.e(TAG, "授权成功");
            }
        }
    }
    
    private static void parseShareResp(int code, Callback callback) {
        callback.callback(code);
        if (BuildConfig.DEBUG) {
            if (code == ErrCode.CANCEL) {
                Logger.e(TAG, "用户取消授权");
            } else if (code != ErrCode.SUCCESS) {
                Logger.e(TAG, "授权失败");
            } else {
                Logger.e(TAG, "授权成功");
            }
        }
    }
    
    public static void authLogin(@NonNull Activity activity, @NonNull String appId, @NonNull LoginCallback callback) throws IllegalArgumentException {
        QQAPI api = QQAPI.getApi(activity, appId);
        int code = checkApi(activity, api);
        if (code != ErrCode.SUCCESS) {
            callback.callback(code, null, null);
            return;
        }
        
        LoginCallback loginCallback = new LoginCallback() {
            @Override
            public void callback(int code, String openId, String accessToken) {
                api.mLoginEventHandler.unregisterOnWXRespCallback(this);
                parseLoginResp(code, openId, accessToken, callback);
            }
        };
        api.mLoginEventHandler.registerOnWXRespCallback(loginCallback);
        api.mApi.login(activity, "get_user_info", api.mLoginEventHandler);
    }
    
    private static int checkApi(@NonNull Activity activity, QQAPI api) {
        Tencent tencent = api.mApi;
        if (tencent == null) {
            Logger.e(TAG, "tencent api创建失败");
            return ErrCode.FAILED;
        }
        
        if (!tencent.isQQInstalled(activity)) {
            Logger.e(TAG, "app未安装");
            return ErrCode.APP_NOT_INSTALL;
        }
        
        return ErrCode.SUCCESS;
    }
    
    public static void shareTextData(@NonNull Activity activity, @NonNull String appId, @NonNull String content, Callback callback) throws IllegalArgumentException {
        QQAPI api = QQAPI.getApi(activity, appId);
        int code = checkApi(activity, api);
        if (code != ErrCode.SUCCESS) {
            callback.callback(code);
            return;
        }
        
        final Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
        sendIntent.putExtra(Intent.EXTRA_TEXT, content);
        sendIntent.setType("text/*");
        // 普通大众版 > 办公简洁版 > 急速轻聊版
        PackageManager packageManager = activity.getPackageManager();
        for (String packageName : Arrays.asList("com.tencent.mobileqq", "com.tencent.tim", "com.tencent.qqlite")) {
            sendIntent.setPackage(packageName);
            if (sendIntent.resolveActivity(packageManager) != null) {
                sendIntent.setComponent(new ComponentName(packageName, "com.tencent.mobileqq.activity.JumpActivity"));
                try {
                    // 必须构建chooserIntent，且设置：sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    // 否则拉起QQ分享界面关闭后再次打开，还是停留在分享界面，不知道是不是QQ的Bug
                    sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    Intent chooserIntent = Intent.createChooser(sendIntent, null);
                    activity.startActivityForResult(chooserIntent, SHARE_TEXT);
                    // 等从QQ回来时才回调结果
                    if (callback != null) {
                        LoginCallback respCallback = new LoginCallback() {
                            @Override
                            public void callback(int code, String openId, String accessToken) {
                                api.mShareEventHandler.unregisterOnWXRespCallback(this);
                                parseShareResp(code, callback);
                            }
                        };
                        api.mShareEventHandler.registerOnWXRespCallback(respCallback);
                    }
                } catch (Exception e) {
                    Logger.e(TAG, "打开QQ失败");
                    if (callback != null) {
                        callback.callback(ErrCode.FAILED);
                    }
                }
                return;
            }
        }
        
        if (callback != null) {
            callback.callback(ErrCode.FAILED);
        }
    }
    
    public static void shareWebData(@NonNull Activity activity, @NonNull String appId, @NonNull String url,
                                    String title, String desc, String iconUrl, Callback callback) throws IllegalArgumentException {
        final Bundle params = new Bundle();
        params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);
        params.putString(QQShare.SHARE_TO_QQ_TITLE, title);
        params.putString(QQShare.SHARE_TO_QQ_SUMMARY, desc);
        params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, url);
        params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, iconUrl);
        params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE);
        shareData(activity, appId, params, callback);
    }
    
    public static void shareImageData(@NonNull Activity activity, @NonNull String appId, @NonNull String localPath, Callback callback) throws IllegalArgumentException {
        final Bundle params = new Bundle();
        params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_IMAGE);
        params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, localPath);
        params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE);
        shareData(activity, appId, params, callback);
    }
    
    private static void shareData(@NonNull Activity activity, @NonNull String appId, @NonNull Bundle params, Callback callback) throws IllegalArgumentException {
        QQAPI api = QQAPI.getApi(activity, appId);
        int code = checkApi(activity, api);
        if (code != ErrCode.SUCCESS) {
            callback.callback(code);
            return;
        }
        
        if (callback != null) {
            LoginCallback respCallback = new LoginCallback() {
                @Override
                public void callback(int code, String openId, String accessToken) {
                    api.mShareEventHandler.unregisterOnWXRespCallback(this);
                    parseShareResp(code, callback);
                }
            };
            api.mShareEventHandler.registerOnWXRespCallback(respCallback);
        }
        api.mApi.shareToQQ(activity, params, api.mShareEventHandler);
    }
    
    public interface LoginCallback {
        /**
         * @param code        授权结果：{@link ErrCode}
         * @param openId      用户唯一Id
         * @param accessToken 访问用户用户数据令牌
         */
        void callback(int code, String openId, String accessToken);
    }
    
    public interface Callback {
        /**
         * @param code 授权结果：{@link ErrCode}
         */
        void callback(int code);
    }
    
    private static class QQApiEventHandlerImpl implements IUiListener {
        private final ArrayList<LoginCallback> onRespCallbacks = new ArrayList<>();
        
        public void registerOnWXRespCallback(LoginCallback on) {
            this.onRespCallbacks.add(on);
        }
        
        public void unregisterOnWXRespCallback(LoginCallback on) {
            this.onRespCallbacks.remove(on);
        }
        
        @Override
        public void onComplete(Object response) {
            int code = ErrCode.FAILED;
            String openid = null;
            String token = null;
            if (response instanceof JSONObject) {
                JSONObject object = (JSONObject) response;
                int ret = object.optInt("ret", -1);
                if (ret == 0) {
                    openid = object.optString(Constants.PARAM_OPEN_ID);
                    token = object.optString(Constants.PARAM_ACCESS_TOKEN);
                    code = ErrCode.SUCCESS;
                } else if (ret == 100013) {
                    code = ErrCode.CANCEL;
                }
            }
            
            onCallback(code, openid, token);
        }
        
        @Override
        public void onError(UiError uiError) {
            onCallback(ErrCode.FAILED, null, null);
        }
        
        @Override
        public void onCancel() {
            onCallback(ErrCode.CANCEL, null, null);
        }
        
        @Override
        public void onWarning(int i) {
        
        }
        
        public void onCallback(int code, String openId, String accessToken) {
            ArrayList<LoginCallback> callbacks = new ArrayList<>(onRespCallbacks);
            for (LoginCallback callback : callbacks) {
                callback.callback(code, openId, accessToken);
            }
        }
    }
}

